package com.test;

import java.io.File;
import java.io.IOException;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FileUtils;


public class Compare2Dirs {

	static int flag = 0;
	
	public static void main(String[] args) throws IOException {
		long start = System.currentTimeMillis();
		String root = args[0];
		String[] path  = new String[]{root + "new/" , root + "old/" , root +"target/"};
		if (path.length < 3) {
			System.out.println("错误的参数:" + path[0]);
			return;
		}
		Timestamp time = new Timestamp(start);
		DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		System.out.println(sdf.format(time) + "---开始备份到target......");
		FileUtil.main(path);
		
		time = new Timestamp(System.currentTimeMillis());
		System.out.println(sdf.format(time) + "---备份到target完成。");
		
		time = new Timestamp(System.currentTimeMillis());
		System.out.println(sdf.format(time) + "---开始比较文件......");
		
		String dir1 = path[0];
		String dir2 = path[1];
		// 获取path1,path2的所有文件夹路径,文件的md5值put map
		Map<String, FileMd5> path1Map = listDir(dir1);
		Map<String, FileMd5> path2Map = listDir(dir2);
		// compare path1 map to path2 map 得到path2没有的文件夹和文件及其md5值不同的文件
		List<FileMd5> compareFile1 = compareFile(path1Map, path2Map);
		// compare path2 map to path1 map 得到path1没有的文件夹和文件及其md5值不同的文件
//		List<FileMd5> compareFile2 = compareFile(path2Map, path1Map);
		
		time = new Timestamp(System.currentTimeMillis());
		System.out.println(sdf.format(time) + "---共更新的文件 " + compareFile1.size() + " 个。");
//		System.out.println("compareFile2 size = " + compareFile2.size());
		// 过滤结果
//		List<FileMd5> equalsFile = filterFile(compareFile1, compareFile2);
//		// 输出最终结果
//		printResult(equalsFile, compareFile1, compareFile2);
		
		time = new Timestamp(System.currentTimeMillis());
		System.out.println(sdf.format(time) + "---比较文件结束。");
		
		time = new Timestamp(System.currentTimeMillis());
		System.out.println(sdf.format(time) + "---开始删除旧文件(只保留新文件)......");
//		try {
//			Thread.sleep(1000);
//		} catch (InterruptedException e) {
//			e.printStackTrace();
//		}
		
		delTarget(compareFile1, path[2]);
		time = new Timestamp(System.currentTimeMillis());
		System.out.println(sdf.format(time) + "---删除旧文件完成。");
		
		long end = System.currentTimeMillis();
		
		long time0  = end-start;
		
		
		System.out.println(sdf.format(end) + "---任务完成，共耗时 " + (time0/1000) + " 秒。");
		
	}

	/**
	 * 获取指定路径下的所有文件路径
	 */
	private static List<File> listPath(File path) {
		List<File> list = new ArrayList<File>();
		File[] files = path.listFiles();
		Arrays.sort(files);
		for (File file : files) {
			list.add(file);
			if (file.isDirectory()) {
				List<File> _list = listPath(file);
				list.addAll(_list);
			}
		}
		return list;
	}

	/**
	 * 获取指定文件夹下的文件夹路径和文件md5值
	 */
	private static Map<String, FileMd5> listDir(String dir) throws IOException {
		Map<String, FileMd5> map = new HashMap<String, FileMd5>();
		File path = new File(dir);
		Object[] files = listPath(path).toArray();
		Arrays.sort(files);
		for (Object _file : files) {
			File file = (File) _file;
			String key = file.getAbsolutePath().replaceAll("\\\\", "/");
			key = key.replaceAll(dir, "");// 去掉根目录
			String md5 = "";// 文件夹的md5默认为空,即不比较md5值
			if (file.isFile()) {
				String text = FileUtils.readFileToString(file);
				md5 = DigestUtils.md5Hex(text);
			}
			FileMd5 fileMd5 = new FileMd5(file, md5);
			map.put(key, fileMd5);
		}
		return map;
	}

	/**
	 * 比较两个文件夹的不同
	 */
	public static List<FileMd5> compareFile(Map<String, FileMd5> path1Map,
			Map<String, FileMd5> path2Map) {
		List<FileMd5> list = new ArrayList<FileMd5>();
		for (String key : path1Map.keySet()) {
			FileMd5 fileMd5 = path1Map.get(key);
			FileMd5 _fileMd5 = path2Map.get(key);

			// 不管文件夹还是文件，只要path2没有则add到比较结果集中
			if (_fileMd5 == null) {
				list.add(fileMd5);
				continue;
			}

			// 文件的md5值不同则add到比较结果集中
			if (fileMd5.getFile().isFile()
					&& !fileMd5.getMd5().equals(_fileMd5.getMd5())) {
				list.add(fileMd5);
			}
		}
		return list;
	}

	/**
	 * 过滤相同
	 */
	public static List<FileMd5> filterFile(List<FileMd5> compareFile1,
			List<FileMd5> compareFile2) {
		List<FileMd5> list = new ArrayList<FileMd5>();
		for (FileMd5 fileMd5 : compareFile1) {
			if (compareFile2.contains(fileMd5)) {
				list.add(fileMd5);// 千万不要在此remove fileMd5
			}
		}
		// remove equals fileMd5
		for (FileMd5 fileMd5 : list) {
			compareFile1.remove(fileMd5);
			compareFile2.remove(fileMd5);
		}
		return list;
	}

	/**
	 * 打印结果
	 */
	public static void printResult(List<FileMd5> equalsFile,List<FileMd5> compareFile1, List<FileMd5> compareFile2) {
		System.out.println("#####比较结果#####");
//		System.out.println("#####均不同的结果#####");
//		printFile(equalsFile);
//		System.out.println("#####均不同的结果#####");
		System.out.println("#####path1多的结果#####");
		printFile(compareFile1);
		System.out.println("#####path1多的结果#####");
//		System.out.println("#####path2多的结果#####");
//		printFile(compareFile2);
//		System.out.println("#####path2多的结果#####");
	}

	/**
	 * 打印结果
	 */
	public static void printFile(List<FileMd5> fileMd5s) {
		for (FileMd5 fileMd5 : fileMd5s) {
			System.out.println(fileMd5.getFile().getAbsolutePath() + " "
					+ fileMd5.getMd5());
		}
	}
	
	public static void delTarget(List<FileMd5> fileMd5s,String target){
		List<File> targetList =  listPath(new File(target));
//		System.out.println("targetList size= " + targetList.size());
		String path;
		String delPath;
		Map<String,String> map = new HashMap<String, String>();
		
		for(FileMd5 fileMd5 : fileMd5s){
			delPath = fileMd5.getFile().getAbsolutePath();
			delPath = delPath.replace("new", "target");
//			System.out.println("delPath = " + delPath);
			map.put(delPath, delPath);
		}
		
		for(File file :targetList){
			if(file.isDirectory()){
				if(file.listFiles().length ==0){
					file.delete();
//					System.out.println("del Directory " +(flag++) + ": " + file.getAbsolutePath());
				}
				continue;
			}
			path = file.getAbsolutePath();
			
			if(map.get(path) == null){
				file.delete();
//				System.out.println("del " +(flag++) + ": " + path);
			}
		}
		
		for(int i = 0 ; i < 10 ; i ++){
			delBlankDir(target);
			
		}		
	}

	/**
	 * 删除空目录
	 * @param filepath
	 */
	public static void delBlankDir(String filepath)  {
        File file = new File(filepath);// 定义文件路径
        if (file.exists() && file.isDirectory()) {// 判断是文件还是目录
            if (file.listFiles().length == 0) {// 若目录下没有文件则直接删除
                file.delete();
//                System.out.println("del " +(flag++) + ": "  + file.getAbsolutePath());
            } else {// 若有则把文件放进数组，并判断是否有下级目录
                File delFile[] = file.listFiles();
                int i = file.listFiles().length;
                for (int j = 0; j < i; j++) {
                    if (delFile[j].isDirectory()) {
                    	delBlankDir(delFile[j].getAbsolutePath());// 递归调用del方法并取得子目录路径
                    }
                }
            }
        }
    }
}

